TypeScriptμμ JWTλ₯Ό μ¬μ©νμ¬ κ°λ ₯νκ³ νμ μμ ν μΈμ¦ ν¨ν΄μ νμνκ³ μμ νκ³ μ μ§ κ΄λ¦¬ κ°λ₯ν κΈλ‘λ² μ ν리μΌμ΄μ μ 보μ₯ν©λλ€. ν₯μλ νμ μμ μ±μΌλ‘ μ¬μ©μ λ°μ΄ν°, μν λ° κΆνμ κ΄λ¦¬νλ λͺ¨λ² μ¬λ‘λ₯Ό μμ보μΈμ.
TypeScript Authentication: JWT Type Safety Patterns for Global Applications
μ€λλ μ μνΈ μ°κ²°λ μΈκ³μμ μμ νκ³ μμ μ μΈ κΈλ‘λ² μ ν리μΌμ΄μ μ ꡬμΆνλ κ²μ΄ κ°μ₯ μ€μν©λλ€. μ¬μ©μ μ μμ νμΈνλ νλ‘μΈμ€μΈ μΈμ¦μ μ€μν λ°μ΄ν°λ₯Ό 보νΈνκ³ μΉμΈλ μ‘μΈμ€λ₯Ό 보μ₯νλ λ° μ€μν μν μ ν©λλ€. JSON μΉ ν ν°(JWT)μ λ¨μμ±κ³Ό μ΄μμ±μΌλ‘ μΈν΄ μΈμ¦μ ꡬννλ λ° λ리 μ¬μ©λλ μ ν μ¬νμ΄ λμμ΅λλ€. TypeScriptμ κ°λ ₯ν νμ μμ€ν κ³Ό κ²°ν©νλ©΄ νΉν λκ·λͺ¨ κ΅μ νλ‘μ νΈμ κ²½μ° JWT μΈμ¦μ λμ± κ°λ ₯νκ³ μ μ§ κ΄λ¦¬ κ°λ₯νκ² λ§λ€ μ μμ΅λλ€.
Why Use TypeScript for JWT Authentication?
TypeScriptλ μΈμ¦ μμ€ν μ ꡬμΆν λ λ€μκ³Ό κ°μ λͺ κ°μ§ μ΄μ μ μ 곡ν©λλ€.
- Type Safety: TypeScriptμ μ μ νμ΄νμ κ°λ° νλ‘μΈμ€ μ΄κΈ°μ μ€λ₯λ₯Ό ν¬μ°©νμ¬ λ°νμμ μμμΉ λͺ»ν λ¬Έμ κ° λ°μν μνμ μ€μ λλ€. μ΄λ μΈμ¦κ³Ό κ°μ 보μμ λ―Όκ°ν κ΅¬μ± μμμ λ§€μ° μ€μν©λλ€.
- Improved Code Maintainability: μ νμ λͺ νν κ³μ½ λ° λ¬Έμλ₯Ό μ 곡νμ¬ νΉν μ¬λ¬ κ°λ°μκ° μ°Έμ¬ν μ μλ 볡μ‘ν κΈλ‘λ² μ ν리μΌμ΄μ μμ μ½λλ₯Ό λ μ½κ² μ΄ν΄, μμ λ° λ¦¬ν©ν°λ§ν μ μλλ‘ ν©λλ€.
- Enhanced Code Completion and Tooling: TypeScriptλ₯Ό μΈμνλ IDEλ λ λμ μ½λ μμ±, νμ λ° λ¦¬ν©ν°λ§ λꡬλ₯Ό μ 곡νμ¬ κ°λ°μ μμ°μ±μ ν₯μμν΅λλ€.
- Reduced Boilerplate: μΈν°νμ΄μ€ λ° μ λ€λ¦κ³Ό κ°μ κΈ°λ₯μ μμ©κ΅¬ μ½λλ₯Ό μ€μ΄κ³ μ½λ μ¬μ¬μ©μ±μ κ°μ νλ λ° λμμ΄ λ μ μμ΅λλ€.
Understanding JWTs
JWTλ λ λΉμ¬μ κ°μ μ μ‘λ ν΄λ μμ λνλ΄λ μκ³ URL μμ ν μλ¨μ λλ€. μΈ λΆλΆμΌλ‘ ꡬμ±λ©λλ€.
- Header: μκ³ λ¦¬μ¦κ³Ό ν ν° μ νμ μ§μ ν©λλ€.
- Payload: μ¬μ©μ ID, μν λ° λ§λ£ μκ°κ³Ό κ°μ ν΄λ μμ΄ ν¬ν¨λμ΄ μμ΅λλ€.
- Signature: λΉλ° ν€λ₯Ό μ¬μ©νμ¬ ν ν°μ 무결μ±μ 보μ₯ν©λλ€.
JWTλ κ° μμ²μ λν΄ λ°μ΄ν°λ² μ΄μ€λ₯Ό 쿼리ν νμ μμ΄ μλ² μΈ‘μμ μ½κ² νμΈν μ μκΈ° λλ¬Έμ μΌλ°μ μΌλ‘ μΈμ¦μ μ¬μ©λ©λλ€. κ·Έλ¬λ μ€μν μ 보λ₯Ό JWT νμ΄λ‘λμ μ§μ μ μ₯νλ κ²μ μΌλ°μ μΌλ‘ κΆμ₯λμ§ μμ΅λλ€.
Implementing Type-Safe JWT Authentication in TypeScript
TypeScriptμμ νμ μμ ν JWT μΈμ¦ μμ€ν μ ꡬμΆνκΈ° μν λͺ κ°μ§ ν¨ν΄μ μ΄ν΄λ³΄κ² μ΅λλ€.
1. Defining Payload Types with Interfaces
JWT νμ΄λ‘λμ ꡬ쑰λ₯Ό λνλ΄λ μΈν°νμ΄μ€λ₯Ό μ μνμ¬ μμν©λλ€. μ΄λ κ² νλ©΄ ν ν° λ΄μμ ν΄λ μμ μ‘μΈμ€ν λ νμ μμ μ±μ ν보ν μ μμ΅λλ€.
interface JwtPayload {
userId: string;
email: string;
roles: string[];
iat: number; // Issued At (timestamp)
exp: number; // Expiration Time (timestamp)
}
μ΄ μΈν°νμ΄μ€λ JWT νμ΄λ‘λμ μμλλ λͺ¨μμ μ μν©λλ€. ν ν° μ ν¨μ± κ΄λ¦¬μ μ€μν νμ€ JWT ν΄λ μμΈ `iat`(λ°ν μκ°) λ° `exp`(λ§λ£ μκ°)λ₯Ό ν¬ν¨νμ΅λλ€. μ¬μ©μ μν λλ κΆνκ³Ό κ°μ΄ μ ν리μΌμ΄μ κ³Ό κ΄λ ¨λ λ€λ₯Έ ν΄λ μμ μΆκ°ν μ μμ΅λλ€. ν ν° ν¬κΈ°λ₯Ό μ΅μννκ³ λ³΄μμ κ°μ νκΈ° μν΄ ν΄λ μμ νμν μ 보λ‘λ§ μ ννλ κ²μ΄ μ’μ΅λλ€.
Example: Handling User Roles in a Global E-commerce Platform
μ μΈκ³ κ³ κ°μκ² μλΉμ€λ₯Ό μ 곡νλ μ μ μκ±°λ νλ«νΌμ κ³ λ €ν΄ λ³΄μμμ€. μ¬μ©μμ λ°λΌ μν μ΄ λ€λ¦ λλ€.
- Admin: μ ν, μ¬μ©μ λ° μ£Όλ¬Έμ κ΄λ¦¬ν μ μλ μ 체 μ‘μΈμ€ κΆνμ΄ μμ΅λλ€.
- Seller: μμ μ μ νμ μΆκ°νκ³ κ΄λ¦¬ν μ μμ΅λλ€.
- Customer: μ νμ μ°Ύμλ³΄κ³ κ΅¬λ§€ν μ μμ΅λλ€.
`JwtPayload`μ `roles` λ°°μ΄μ μ¬μ©νμ¬ μ΄λ¬ν μν μ λνλΌ μ μμ΅λλ€. `roles` μμ±μ λ³΄λ€ λ³΅μ‘ν κ΅¬μ‘°λ‘ νμ₯νμ¬ μ¬μ©μμ μ‘μΈμ€ κΆνμ μΈλΆνλ λ°©μμΌλ‘ λνλΌ μ μμ΅λλ€. μλ₯Ό λ€μ΄ μ¬μ©μκ° νλ§€μλ‘ μ΄μν μ μλ κ΅κ° λͺ©λ‘ λλ μ¬μ©μκ° κ΄λ¦¬μ μ‘μΈμ€ κΆνμ κ°μ§ μμ λ°°μ΄μ κ°μ§ μ μμ΅λλ€.
2. Creating a Typed JWT Service
JWT μμ± λ° νμΈμ μ²λ¦¬νλ μλΉμ€λ₯Ό λ§λλλ€. μ΄ μλΉμ€λ `JwtPayload` μΈν°νμ΄μ€λ₯Ό μ¬μ©νμ¬ νμ μμ μ±μ 보μ₯ν΄μΌ ν©λλ€.
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key'; // Store securely!
class JwtService {
static sign(payload: Omit, expiresIn: string = '1h'): string {
const now = Math.floor(Date.now() / 1000);
const payloadWithTimestamps: JwtPayload = {
...payload,
iat: now,
exp: now + parseInt(expiresIn) * 60 * 60,
};
return jwt.sign(payloadWithTimestamps, JWT_SECRET);
}
static verify(token: string): JwtPayload | null {
try {
const decoded = jwt.verify(token, JWT_SECRET) as JwtPayload;
return decoded;
} catch (error) {
console.error('JWT verification error:', error);
return null;
}
}
}
μ΄ μλΉμ€λ λ κ°μ§ λ°©λ²μ μ 곡ν©λλ€.
- `sign()`: νμ΄λ‘λμμ JWTλ₯Ό λ§λλλ€. `iat` λ° `exp`κ° μλμΌλ‘ μμ±λλλ‘ `Omit
`λ₯Ό μ¬μ©ν©λλ€. `JWT_SECRET`λ₯Ό μμ νκ² μ μ₯νλ κ²μ΄ μ€μν©λλ€. μ΄μμ μΌλ‘λ νκ²½ λ³μ λ° λΉλ° κ΄λ¦¬ μ루μ μ μ¬μ©ν©λλ€. - `verify()`: JWTλ₯Ό νμΈνκ³ μ ν¨ν κ²½μ° λμ½λ©λ νμ΄λ‘λλ₯Ό λ°ννκ³ μ ν¨νμ§ μμ κ²½μ° `null`μ λ°νν©λλ€. `jwt.verify` λ©μλλ μ€λ₯λ₯Ό λ°μμν€κ±°λ(`catch` λΈλ‘μμ μ‘ν) μ μν νμ΄λ‘λ ꡬ쑰μ μΌμΉνλ κ°μ²΄λ₯Ό λ°ννκΈ° λλ¬Έμ νμΈ ν νμ μ΄μ€μ `as JwtPayload`λ₯Ό μ¬μ©ν©λλ€.
Important Security Considerations:
- Secret Key Management: μ½λμ JWT λΉλ° ν€λ₯Ό νλ μ½λ©νμ§ λ§μμμ€. νκ²½ λ³μ λλ μ μ© λΉλ° κ΄λ¦¬ μλΉμ€λ₯Ό μ¬μ©νμμμ€. ν€λ₯Ό μ κΈ°μ μΌλ‘ μννμμμ€.
- Algorithm Selection: HS256 λλ RS256κ³Ό κ°μ κ°λ ₯ν μλͺ μκ³ λ¦¬μ¦μ μ ννμμμ€. `none`κ³Ό κ°μ μ½ν μκ³ λ¦¬μ¦μ νΌνμμμ€.
- Token Expiration: μμλ ν ν°μ μν₯μ μ ννκΈ° μν΄ JWTμ μ μ ν λ§λ£ μκ°μ μ€μ νμμμ€.
- Token Storage: ν΄λΌμ΄μΈνΈ μΈ‘μμ JWTλ₯Ό μμ νκ² μ μ₯νμμμ€. μ΅μ μλ HTTP μ μ© μΏ ν€ λλ XSS 곡격μ λν μ μ ν μλ°© μ‘°μΉλ₯Ό μ·¨ν λ‘컬 μ€ν 리μ§κ° ν¬ν¨λ©λλ€.
3. Protecting API Endpoints with Middleware
`Authorization` ν€λμμ JWTλ₯Ό νμΈνμ¬ API μλν¬μΈνΈλ₯Ό 보νΈνλ λ―Έλ€μ¨μ΄λ₯Ό λ§λλλ€.
import { Request, Response, NextFunction } from 'express';
interface RequestWithUser extends Request {
user?: JwtPayload;
}
function authenticate(req: RequestWithUser, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({ message: 'Unauthorized' });
}
const token = authHeader.split(' ')[1]; // Assuming Bearer token
const decoded = JwtService.verify(token);
if (!decoded) {
return res.status(401).json({ message: 'Invalid token' });
}
req.user = decoded;
next();
}
export default authenticate;
μ΄ λ―Έλ€μ¨μ΄λ `Authorization` ν€λμμ JWTλ₯Ό μΆμΆνκ³ `JwtService`λ₯Ό μ¬μ©νμ¬ νμΈνκ³ λμ½λ©λ νμ΄λ‘λλ₯Ό `req.user` κ°μ²΄μ 첨λΆν©λλ€. λν Express.jsμμ νμ€ `Request` μΈν°νμ΄μ€λ₯Ό νμ₯νλ `RequestWithUser` μΈν°νμ΄μ€λ₯Ό μ μνμ¬ `JwtPayload | undefined` νμ μ `user` μμ±μ μΆκ°ν©λλ€. μ΄λ κ² νλ©΄ 보νΈλ κ²½λ‘μμ μ¬μ©μ μ 보μ μ‘μΈμ€ν λ νμ μμ μ±μ΄ μ 곡λ©λλ€.
Example: Handling Time Zones in a Global Application
μ ν리μΌμ΄μ μμ λ€λ₯Έ μκ°λμ μ¬μ©μκ° μ΄λ²€νΈλ₯Ό μμ½ν μ μλ€κ³ κ°μ ν΄ λ³΄κ² μ΅λλ€. μ΄λ²€νΈ μκ°μ μ¬λ°λ₯΄κ² νμνκΈ° μν΄ μ¬μ©μμ μ νΈ μκ°λλ₯Ό JWT νμ΄λ‘λμ μ μ₯ν μ μμ΅λλ€. `JwtPayload` μΈν°νμ΄μ€μ `timeZone` ν΄λ μμ μΆκ°ν μ μμ΅λλ€.
interface JwtPayload {
userId: string;
email: string;
roles: string[];
timeZone: string; // e.g., 'America/Los_Angeles', 'Asia/Tokyo'
iat: number;
exp: number;
}
κ·Έλ° λ€μ λ―Έλ€μ¨μ΄ λλ κ²½λ‘ μ²λ¦¬κΈ°μμ `req.user.timeZone`μ μ‘μΈμ€νμ¬ μ¬μ©μ κΈ°λ³Έ μ€μ μ λ°λΌ λ μ§ λ° μκ°μ ν¬λ§·ν μ μμ΅λλ€.
4. Using the Authenticated User in Route Handlers
보νΈλ κ²½λ‘ μ²λ¦¬κΈ°μμ μ΄μ μμ ν νμ μμ μ±μΌλ‘ `req.user` κ°μ²΄λ₯Ό ν΅ν΄ μΈμ¦λ μ¬μ©μμ μ 보μ μ‘μΈμ€ν μ μμ΅λλ€.
import express, { Request, Response } from 'express';
import authenticate from './middleware/authenticate';
const app = express();
app.get('/profile', authenticate, (req: Request, res: Response) => {
const user = (req as any).user; // or use RequestWithUser
res.json({ message: `Hello, ${user.email}!`, userId: user.userId });
});
μ΄ μμ μμλ `req.user` κ°μ²΄μμ μΈμ¦λ μ¬μ©μμ μ΄λ©μΌκ³Ό IDμ μ‘μΈμ€νλ λ°©λ²μ 보μ¬μ€λλ€. `JwtPayload` μΈν°νμ΄μ€λ₯Ό μ μνκΈ° λλ¬Έμ TypeScriptλ `user` κ°μ²΄μ μμ ꡬ쑰λ₯Ό μκ³ νμ κ²μ¬ λ° μ½λ μμ±μ μ 곡ν μ μμ΅λλ€.
5. Implementing Role-Based Access Control (RBAC)
λ³΄λ€ μΈλΆνλ μ‘μΈμ€ μ μ΄λ₯Ό μν΄ JWT νμ΄λ‘λμ μ μ₯λ μν μ κΈ°λ°μΌλ‘ RBACλ₯Ό ꡬνν μ μμ΅λλ€.
function authorize(roles: string[]) {
return (req: RequestWithUser, res: Response, next: NextFunction) => {
const user = req.user;
if (!user || !user.roles.some(role => roles.includes(role))) {
return res.status(403).json({ message: 'Forbidden' });
}
next();
};
}
μ΄ `authorize` λ―Έλ€μ¨μ΄λ μ¬μ©μμ μν μ νμν μν μ΄ ν¬ν¨λμ΄ μλμ§ νμΈν©λλ€. κ·Έλ μ§ μμΌλ©΄ 403 Forbidden μ€λ₯λ₯Ό λ°νν©λλ€.
app.get('/admin', authenticate, authorize(['admin']), (req: Request, res: Response) => {
res.json({ message: 'Welcome, Admin!' });
});
μ΄ μμ μμλ μ¬μ©μκ° `admin` μν μ κ°λλ‘ μꡬνμ¬ `/admin` κ²½λ‘λ₯Ό 보νΈν©λλ€.
Example: Handling Different Currencies in a Global Application
μ ν리μΌμ΄μ μμ κΈμ΅ κ±°λλ₯Ό μ²λ¦¬νλ κ²½μ° μ¬λ¬ ν΅νλ₯Ό μ§μν΄μΌ ν μ μμ΅λλ€. μ¬μ©μμ μ νΈ ν΅νλ₯Ό JWT νμ΄λ‘λμ μ μ₯ν μ μμ΅λλ€.
interface JwtPayload {
userId: string;
email: string;
roles: string[];
currency: string; // e.g., 'USD', 'EUR', 'JPY'
iat: number;
exp: number;
}
κ·Έλ° λ€μ λ°±μλ λ‘μ§μμ `req.user.currency`λ₯Ό μ¬μ©νμ¬ κ°κ²©μ ν¬λ§·νκ³ νμμ λ°λΌ ν΅ν λ³νμ μνν μ μμ΅λλ€.
6. Refresh Tokens
JWTλ μ€κ³μ μλͺ μ΄ μ§§μ΅λλ€. μ¬μ©μκ° μμ£Ό λ‘κ·ΈμΈνμ§ μλλ‘ νλ €λ©΄ μλ‘ κ³ μΉ¨ ν ν°μ ꡬννμμμ€. μλ‘ κ³ μΉ¨ ν ν°μ μ¬μ©μκ° μ격 μ¦λͺ μ λ€μ μ λ ₯νμ§ μκ³ λ μ μ‘μΈμ€ ν ν°(JWT)μ μ»λ λ° μ¬μ©ν μ μλ μλͺ μ΄ κΈ΄ ν ν°μ λλ€. μλ‘ κ³ μΉ¨ ν ν°μ λ°μ΄ν°λ² μ΄μ€μ μμ νκ² μ μ₯νκ³ μ¬μ©μμ μ°κ²°νμμμ€. μ¬μ©μ μ‘μΈμ€ ν ν°μ΄ λ§λ£λλ©΄ μλ‘ κ³ μΉ¨ ν ν°μ μ¬μ©νμ¬ μ ν ν°μ μμ²ν μ μμ΅λλ€. μ΄ νλ‘μΈμ€λ 보μ μ·¨μ½μ μ νΌνκΈ° μν΄ μ μ€νκ² κ΅¬νν΄μΌ ν©λλ€.
Advanced Type Safety Techniques
1. Discriminated Unions for Fine-Grained Control
κ²½μ°μ λ°λΌ μ¬μ©μμ μν λλ μμ² μ νμ λ°λΌ λ€λ₯Έ JWT νμ΄λ‘λκ° νμν μ μμ΅λλ€. νλ³λ μ λμ¨μ νμ μμ μ±μΌλ‘ μ΄λ₯Ό λ¬μ±νλ λ° λμμ΄ λ μ μμ΅λλ€.
interface AdminJwtPayload {
type: 'admin';
userId: string;
email: string;
roles: string[];
iat: number;
exp: number;
}
interface UserJwtPayload {
type: 'user';
userId: string;
email: string;
iat: number;
exp: number;
}
type JwtPayload = AdminJwtPayload | UserJwtPayload;
function processToken(payload: JwtPayload) {
if (payload.type === 'admin') {
console.log('Admin email:', payload.email); // Safe to access email
} else {
// payload.email is not accessible here because type is 'user'
console.log('User ID:', payload.userId);
}
}
μ΄ μμ μμλ λ κ°μ λ€λ₯Έ JWT νμ΄λ‘λ νμ μΈ `AdminJwtPayload` λ° `UserJwtPayload`λ₯Ό μ μνκ³ μ΄λ₯Ό νλ³λ μ λμ¨ `JwtPayload`λ‘ κ²°ν©ν©λλ€. `type` μμ±μ νλ³μ μν μ νμ¬ νμ΄λ‘λ νμ μ λ°λΌ μμ±μ μμ νκ² μ‘μΈμ€ν μ μλλ‘ ν©λλ€.
2. Generics for Reusable Authentication Logic
νμ΄λ‘λ κ΅¬μ‘°κ° λ€λ₯Έ μ¬λ¬ μΈμ¦ 체κ³κ° μλ κ²½μ° μ λ€λ¦μ μ¬μ©νμ¬ μ¬μ¬μ© κ°λ₯ν μΈμ¦ λ‘μ§μ λ§λ€ μ μμ΅λλ€.
interface BaseJwtPayload {
userId: string;
iat: number;
exp: number;
}
function verifyToken(token: string): T | null {
try {
const decoded = jwt.verify(token, JWT_SECRET) as T;
return decoded;
} catch (error) {
console.error('JWT verification error:', error);
return null;
}
}
const adminToken = verifyToken('admin-token');
if (adminToken) {
console.log('Admin email:', adminToken.email);
}
μ΄ μμ μμλ `BaseJwtPayload`λ₯Ό νμ₯νλ μ λ€λ¦ νμ `T`λ₯Ό μ¬μ©νλ `verifyToken` ν¨μλ₯Ό μ μν©λλ€. μ΄λ₯Ό ν΅ν΄ λͺ¨λ ν ν°μ μ΅μν `userId`, `iat` λ° `exp` μμ±μ΄ μλμ§ νμΈνλ©΄μ λ€λ₯Έ νμ΄λ‘λ κ΅¬μ‘°λ‘ ν ν°μ νμΈν μ μμ΅λλ€.
Global Application Considerations
κΈλ‘λ² μ ν리μΌμ΄μ μ μν μΈμ¦ μμ€ν μ ꡬμΆν λ λ€μ μ¬νμ κ³ λ €νμμμ€.
- Localization: μ€λ₯ λ©μμ§ λ° μ¬μ©μ μΈν°νμ΄μ€ μμκ° λ€λ₯Έ μΈμ΄ λ° μ§μμ λ§κ² νμ§νλμλμ§ νμΈνμμμ€.
- Time Zones: ν ν° λ§λ£ μκ°μ μ€μ νκ³ λ μ§μ μκ°μ μ¬μ©μμκ² νμν λ μκ°λλ₯Ό μ¬λ°λ₯΄κ² μ²λ¦¬νμμμ€.
- Data Privacy: GDPR λ° CCPAμ κ°μ λ°μ΄ν° κ°μΈ μ 보 λ³΄νΈ κ·μ μ μ€μνμμμ€. JWTμ μ μ₯λ κ°μΈ λ°μ΄ν°μ μμ μ΅μννμμμ€.
- Accessibility: μ₯μ κ° μλ μ¬μ©μκ° μ‘μΈμ€ν μ μλλ‘ μΈμ¦ νλ¦μ μ€κ³νμμμ€.
- Cultural Sensitivity: μ¬μ©μ μΈν°νμ΄μ€ λ° μΈμ¦ νλ¦μ μ€κ³ν λ λ¬Ένμ μ°¨μ΄λ₯Ό μΌλμ λμμμ€.
Conclusion
TypeScriptμ νμ μμ€ν μ νμ©νμ¬ κΈλ‘λ² μ ν리μΌμ΄μ μ μν κ°λ ₯νκ³ μ μ§ κ΄λ¦¬ κ°λ₯ν JWT μΈμ¦ μμ€ν μ ꡬμΆν μ μμ΅λλ€. μΈν°νμ΄μ€λ‘ νμ΄λ‘λ νμ μ μ μνκ³ , νμ νλ JWT μλΉμ€λ₯Ό λ§λ€κ³ , λ―Έλ€μ¨μ΄λ‘ API μλν¬μΈνΈλ₯Ό 보νΈνκ³ , RBACλ₯Ό ꡬννλ κ²μ 보μ λ° νμ μμ μ±μ 보μ₯νλ λ° νμμ μΈ λ¨κ³μ λλ€. νμ§ν, μκ°λ, λ°μ΄ν° κ°μΈ μ 보 보νΈ, μ κ·Όμ± λ° λ¬Ένμ κ°μμ±κ³Ό κ°μ κΈλ‘λ² μ ν리μΌμ΄μ κ³ λ € μ¬νμ κ³ λ €νμ¬ λ€μνκ³ κ΅μ μ μΈ λμμκ² ν¬κ΄μ μ΄κ³ μ¬μ©μ μΉνμ μΈ μΈμ¦ νκ²½μ λ§λ€ μ μμ΅λλ€. μμ ν ν€ κ΄λ¦¬, μκ³ λ¦¬μ¦ μ ν, ν ν° λ§λ£ λ° ν ν° μ€ν 리μ§λ₯Ό ν¬ν¨νμ¬ JWTλ₯Ό μ²λ¦¬ν λ νμ 보μ λͺ¨λ² μ¬λ‘λ₯Ό μ°μ μνμμμ€. TypeScriptμ κΈ°λ₯μ νμ©νμ¬ κΈλ‘λ² μ ν리μΌμ΄μ μ μν μμ νκ³ νμ₯ κ°λ₯νλ©° μμ μ μΈ μΈμ¦ μμ€ν μ ꡬμΆνμμμ€.